package com.kexio.common.util;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * 加密工具类
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
public class EncryptUtils {
    
    /**
     * MD5算法名称
     */
    private static final String MD5 = "MD5";
    
    /**
     * SHA-1算法名称
     */
    private static final String SHA1 = "SHA-1";
    
    /**
     * SHA-256算法名称
     */
    private static final String SHA256 = "SHA-256";
    
    /**
     * SHA-512算法名称
     */
    private static final String SHA512 = "SHA-512";
    
    /**
     * AES算法名称
     */
    private static final String AES = "AES";
    
    /**
     * AES/ECB/PKCS5Padding
     */
    private static final String AES_ECB_PKCS5 = "AES/ECB/PKCS5Padding";
    
    /**
     * HMAC-SHA256算法名称
     */
    private static final String HMAC_SHA256 = "HmacSHA256";
    
    /**
     * 16进制字符
     */
    private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
    
    private EncryptUtils() {
        // 工具类不允许实例化
    }
    
    // ==================== 哈希算法 ====================
    
    /**
     * MD5加密
     */
    public static String md5(String data) {
        return md5(data.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * MD5加密
     */
    public static String md5(byte[] data) {
        return hash(data, MD5);
    }
    
    /**
     * SHA-1加密
     */
    public static String sha1(String data) {
        return sha1(data.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * SHA-1加密
     */
    public static String sha1(byte[] data) {
        return hash(data, SHA1);
    }
    
    /**
     * SHA-256加密
     */
    public static String sha256(String data) {
        return sha256(data.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * SHA-256加密
     */
    public static String sha256(byte[] data) {
        return hash(data, SHA256);
    }
    
    /**
     * SHA-512加密
     */
    public static String sha512(String data) {
        return sha512(data.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * SHA-512加密
     */
    public static String sha512(byte[] data) {
        return hash(data, SHA512);
    }
    
    /**
     * 通用哈希方法
     */
    private static String hash(byte[] data, String algorithm) {
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm);
            byte[] hash = digest.digest(data);
            return bytesToHex(hash);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("不支持的哈希算法: " + algorithm, e);
        }
    }
    
    // ==================== HMAC算法 ====================
    
    /**
     * HMAC-SHA256加密
     */
    public static String hmacSha256(String data, String key) {
        return hmacSha256(data.getBytes(StandardCharsets.UTF_8), key.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * HMAC-SHA256加密
     */
    public static String hmacSha256(byte[] data, byte[] key) {
        try {
            SecretKeySpec secretKey = new SecretKeySpec(key, HMAC_SHA256);
            Mac mac = Mac.getInstance(HMAC_SHA256);
            mac.init(secretKey);
            byte[] hash = mac.doFinal(data);
            return bytesToHex(hash);
        } catch (Exception e) {
            throw new RuntimeException("HMAC-SHA256加密失败", e);
        }
    }
    
    // ==================== AES对称加密 ====================
    
    /**
     * AES加密（使用默认密钥）
     */
    public static String aesEncrypt(String data, String key) {
        return aesEncrypt(data.getBytes(StandardCharsets.UTF_8), key);
    }
    
    /**
     * AES加密
     */
    public static String aesEncrypt(byte[] data, String key) {
        try {
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES);
            Cipher cipher = Cipher.getInstance(AES_ECB_PKCS5);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] encrypted = cipher.doFinal(data);
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            throw new RuntimeException("AES加密失败", e);
        }
    }
    
    /**
     * AES解密
     */
    public static String aesDecrypt(String encryptedData, String key) {
        try {
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES);
            Cipher cipher = Cipher.getInstance(AES_ECB_PKCS5);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] encrypted = Base64.getDecoder().decode(encryptedData);
            byte[] decrypted = cipher.doFinal(encrypted);
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("AES解密失败", e);
        }
    }
    
    /**
     * 生成AES密钥
     */
    public static String generateAESKey() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
            keyGenerator.init(256);
            SecretKey secretKey = keyGenerator.generateKey();
            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("生成AES密钥失败", e);
        }
    }
    
    // ==================== Base64编码 ====================
    
    /**
     * Base64编码
     */
    public static String base64Encode(String data) {
        return base64Encode(data.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * Base64编码
     */
    public static String base64Encode(byte[] data) {
        return Base64.getEncoder().encodeToString(data);
    }
    
    /**
     * Base64解码
     */
    public static String base64Decode(String encodedData) {
        byte[] decoded = Base64.getDecoder().decode(encodedData);
        return new String(decoded, StandardCharsets.UTF_8);
    }
    
    /**
     * Base64解码为字节数组
     */
    public static byte[] base64DecodeToBytes(String encodedData) {
        return Base64.getDecoder().decode(encodedData);
    }
    
    /**
     * URL安全的Base64编码
     */
    public static String base64UrlEncode(String data) {
        return base64UrlEncode(data.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * URL安全的Base64编码
     */
    public static String base64UrlEncode(byte[] data) {
        return Base64.getUrlEncoder().withoutPadding().encodeToString(data);
    }
    
    /**
     * URL安全的Base64解码
     */
    public static String base64UrlDecode(String encodedData) {
        byte[] decoded = Base64.getUrlDecoder().decode(encodedData);
        return new String(decoded, StandardCharsets.UTF_8);
    }
    
    // ==================== 密码相关 ====================
    
    /**
     * 生成随机盐值
     */
    public static String generateSalt() {
        return generateSalt(16);
    }
    
    /**
     * 生成指定长度的随机盐值
     */
    public static String generateSalt(int length) {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[length];
        random.nextBytes(salt);
        return bytesToHex(salt);
    }
    
    /**
     * 密码加盐哈希
     */
    public static String hashPassword(String password, String salt) {
        return sha256(password + salt);
    }
    
    /**
     * 验证密码
     */
    public static boolean verifyPassword(String password, String salt, String hashedPassword) {
        String hash = hashPassword(password, salt);
        return hash.equals(hashedPassword);
    }
    
    /**
     * 生成强密码哈希（自动生成盐值）
     */
    public static PasswordHash hashPasswordWithSalt(String password) {
        String salt = generateSalt();
        String hash = hashPassword(password, salt);
        return new PasswordHash(hash, salt);
    }
    
    /**
     * 密码哈希结果
     */
    public static class PasswordHash {
        private final String hash;
        private final String salt;
        
        public PasswordHash(String hash, String salt) {
            this.hash = hash;
            this.salt = salt;
        }
        
        public String getHash() {
            return hash;
        }
        
        public String getSalt() {
            return salt;
        }
        
        /**
         * 验证密码
         */
        public boolean verify(String password) {
            return verifyPassword(password, salt, hash);
        }
    }
    
    // ==================== 随机数生成 ====================
    
    /**
     * 生成随机字符串
     */
    public static String generateRandomString(int length) {
        return generateRandomString(length, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
    }
    
    /**
     * 生成随机数字字符串
     */
    public static String generateRandomNumber(int length) {
        return generateRandomString(length, "0123456789");
    }
    
    /**
     * 生成随机字母字符串
     */
    public static String generateRandomLetter(int length) {
        return generateRandomString(length, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
    }
    
    /**
     * 从指定字符集生成随机字符串
     */
    public static String generateRandomString(int length, String charset) {
        SecureRandom random = new SecureRandom();
        StringBuilder sb = new StringBuilder(length);
        
        for (int i = 0; i < length; i++) {
            int randomIndex = random.nextInt(charset.length());
            sb.append(charset.charAt(randomIndex));
        }
        
        return sb.toString();
    }
    
    // ==================== 工具方法 ====================
    
    /**
     * 字节数组转16进制字符串
     */
    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int i = 0; i < bytes.length; i++) {
            int v = bytes[i] & 0xFF;
            hexChars[i * 2] = HEX_CHARS[v >>> 4];
            hexChars[i * 2 + 1] = HEX_CHARS[v & 0x0F];
        }
        return new String(hexChars);
    }
    
    /**
     * 16进制字符串转字节数组
     */
    public static byte[] hexToBytes(String hex) {
        if (hex.length() % 2 != 0) {
            throw new IllegalArgumentException("16进制字符串长度必须为偶数");
        }
        
        byte[] bytes = new byte[hex.length() / 2];
        for (int i = 0; i < bytes.length; i++) {
            int high = Character.digit(hex.charAt(i * 2), 16);
            int low = Character.digit(hex.charAt(i * 2 + 1), 16);
            bytes[i] = (byte) ((high << 4) + low);
        }
        return bytes;
    }
    
    /**
     * 生成UUID（去掉连字符）
     */
    public static String generateUUID() {
        return java.util.UUID.randomUUID().toString().replace("-", "");
    }
    
    /**
     * 生成标准UUID
     */
    public static String generateStandardUUID() {
        return java.util.UUID.randomUUID().toString();
    }
}
